// 生成器是es6语法定义的迭代器，适合要迭代的值不是某个数据结构的元素，而是计算结果的场景
// 创建生成器需要先定义一个生成器函数，使用关键字function*，调用生成器函数不会执行函数体，而是返回一个迭代器。
// 调用迭代器的next方法，会导致生成器函数的函数体从头开始执行，知道遇见一个yield语句。yield语句的值，会成为返回值。

// 例1
function* oneDigitPrimes() {
    yield 2;
    yield 3;
    yield 5;
    yield 7;
}
let primes = oneDigitPrimes()
primes.next().value // 2
primes.next().value // 3
console.log(primes.next().value); // 5
console.log(primes.next().done); // false
console.log(primes.next().done); // true

let primesIterator = primes[Symbol.iterator]()// 可迭代对象
console.log(primesIterator.next()); // {value: undefined, done: true}

console.log([...oneDigitPrimes()]); //[2, 3, 5, 7]
let sum = 0
for (const v of oneDigitPrimes()) {
    sum += v
}
console.log(sum); // 17

// 例2
const seq = function* (from, to) {
    for (let i = from; i <= to; i++) yield i
}
console.log([...seq(3, 5)]); // [3, 4,5]

// 例3 类和对象字面量, 不能使用箭头函数定义生成器函数
let o = {
    x: 1, y: 2, z: 3,
    *g() {
        for (const key of Object.keys(this)) {
            yield key
        }
    }
}
console.log([...o.g()]); //["x", "y", "z", "g"]

// 例4 无限回送斐波那契数 如果执行[...fibonacciSequence()]会一直循环直到内存耗尽
function* fibonacciSequence() {
    let x = 0, y = 1;
    while (1) {
        yield y;
        [x, y] = [y, x + y]
    }
}

//通过限制条件， 返回第20个斐波那契数
function fibonacci(n) {
    for (const f of fibonacciSequence()) {
        if (n-- <= 0) {
            return f
        }
    }
}
console.log(fibonacci(10)); //89

// 配合take生成器(用另一个生成器封装一下) 回送指定可迭代对象的前n个元素
function* take(n, iterable) {
    let it = iterable[Symbol.iterator]()
    while (n-- > 0) {
        let next = it.next()
        if (next.done) {
            return
        }
        yield next.value
    }
}
console.log([...take(5, fibonacciSequence())]); //[1, 1, 2, 3, 5]

// 拿到可迭代对象数组，交替回送元素
function* zip(...iterables) {
    // 取得每个可迭代对象的迭代器
    let iterators = iterables.map(i => i[Symbol.iterator]())
    let index = 0
    while (iterators.length > 0) {
        if (index >= iterators.length) {
            index = 0
        }
        let item = iterators[index].next()
        if (item.done) {
            iterators.splice(index, 1)
        }
        else {
            yield item.value
            index++
        }
    }
}
console.log([...zip(oneDigitPrimes(), 'ab', [0])]); //[2, "a", 0, 3, "b", 5, 7]

// yield*与递归生成器
// 顺序回送元素
function* sequence(...iterables) {
    for (const iterable of iterables) {
        for (const item of iterable) {
            yield item;
        }
    }
}
console.log([...sequence("abc", [1, 2, 3])]); // ["a", "b", "c", 1, 2, 3]
// 使用yield* 简化
function* sequence2(...iterables) {
    for (const item of iterables) {
        yield* item
    }
}
console.log([...sequence2('abc', 'def')]); // ["a", "b", "c", "d", "e", "f"]

        // yield 和yield*只能在生成器函数中使用，常规函数不能出现！

